package com.zyw.zhuangdian.service.impl;

import com.zyw.zhuangdian.constant.ServiceConstant;
import com.zyw.zhuangdian.dao.FileDao;
import com.zyw.zhuangdian.enums.MsgCode;
import com.zyw.zhuangdian.pojo.Resp;
import com.zyw.zhuangdian.pojo.dto.FileDto;
import com.zyw.zhuangdian.pojo.dto.PageDto;
import com.zyw.zhuangdian.pojo.in.FileDtoIn;
import com.zyw.zhuangdian.property.MyProperties;
import com.zyw.zhuangdian.service.FileService;
import com.zyw.zhuangdian.util.Base64Util;
import com.zyw.zhuangdian.util.BeanConvertUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;


@Service
public class FileServiceImpl implements FileService {
    private final Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);

    @Autowired
    private MyProperties properties;

    @Autowired
    private FileDao fileDao;

    @Override
    public Resp<Void> deleteFiles(FileDtoIn in) {
        Resp<Void> resp = new Resp<>();
        in.setStatus(ServiceConstant.STATUS_INVALID);
        if (in.getFileIds()!=null && in.getFileIds().size()!=0) {
            fileDao.updateFile(BeanConvertUtil.beanCovertMap(in));
        }
        return resp;
    }

    @Override
    public Resp<List<FileDto>> listFiles(FileDto in) {
        Resp<List<FileDto>> resp = new Resp<>();
        if (in.getPage() != PageDto.DEFAULT_PAGE){
            if (in.getRow() == PageDto.DEFAULT_PAGE){
                in.setPage(PageDto.DEFAULT_PAGE);
            }else{
                in.setPage((in.getPage() - 1) * in.getRow());
            }
        }

        int count = fileDao.listFilesCount(BeanConvertUtil.beanCovertMap(in));
        List<FileDto> fileDtos = new ArrayList<>();
        if (count > 0){
            fileDtos = BeanConvertUtil.covertBeanList(
                    fileDao.listFiles(BeanConvertUtil.beanCovertMap(in)),FileDto.class);
            resp.setData(fileDtos);
        }
        resp.setTotal(count);
        if (in.getPage() != PageDto.DEFAULT_PAGE) {
            resp.setRecords((int) Math.ceil((double) count / (double) in.getRow()));
            resp.setPage(in.getPage());
            resp.setRow(in.getRow());
        }
        return resp;
    }

    @Override
    public Resp<FileDto> saveBase64Image(FileDtoIn in) {
        Resp<FileDto> out = new Resp<>();
        if (StringUtils.isBlank(in.getBase64File())){
            throw new IllegalArgumentException("上传图片内容为空");
        }

        try {
            String base64String = in.getBase64File();
            if (base64String.contains("data:image/png;")){
                base64String = base64String.replace("data:image/png;base64,","");
                in.setFileType("png");
            }else if (base64String.contains("data:image/jpeg;")){
                base64String = base64String.replace("data:image/jpeg;base64,","");
                in.setFileType("jpeg");
            }else if (base64String.contains("data:image/gif;")){
                base64String = base64String.replace("data:image/gif;base64,","");
                in.setFileType("gif");
            }else{
                throw new IllegalArgumentException("不支持的图片格式");
            }
            //Base64解码
            byte[] b = Base64Utils.decodeFromString(base64String);

            // 生成保存路径
            in.setFileMd5("");
            in.setFileName("");
            Resp<String> resp = checkCachedFile(in, b);
            String filename = resp.getData();
            // 当code为success时为新文件，保存
            if (resp.getCode().equals(MsgCode.MSG_SUCCESS.getCode())) {
                //保存图片
                String sb = properties.getUpload_file_location() +
                        File.separator +
                        filename;
                OutputStream localFile = new FileOutputStream(sb);
                localFile.write(b);
                localFile.flush();
                localFile.close();
            }
            FileDto outFileDto = new FileDto();
            outFileDto.setFileName(filename);
            out.setData(outFileDto);
            return out;
        } catch (IOException e) {
            throw new IllegalArgumentException("文件保存失败");
        }
    }

    @Override
    public Resp<List<FileDto>> saveBase64Images(FileDtoIn in) {
        Resp<List<FileDto>> out = new Resp<>();
        if (CollectionUtils.isEmpty(in.getBase64Files())){
            throw new IllegalArgumentException("上传图片内容为空");
        }

        try {
            List<FileDto> outList = new ArrayList<>();
            for (String base64String:in.getBase64Files()) {
                FileDtoIn inData = new FileDtoIn();
                inData.setBase64File(base64String);
                if (base64String.contains("data:image/png;")) {
                    base64String = base64String.replace("data:image/png;base64,", "");
                    inData.setFileType("png");
                } else if (base64String.contains("data:image/jpeg;")) {
                    base64String = base64String.replace("data:image/jpeg;base64,", "");
                    inData.setFileType("jpeg");
                } else if (base64String.contains("data:image/gif;")) {
                    base64String = base64String.replace("data:image/gif;base64,", "");
                    inData.setFileType("gif");
                } else {
                    throw new IllegalArgumentException("不支持的图片格式");
                }
                //Base64解码
                byte[] b = Base64Utils.decodeFromString(base64String);

                // 生成保存路径
                Resp<String> resp = checkCachedFile(inData, b);
                String filename = resp.getData();
                // 当code为success时为新文件，保存
                if (resp.getCode().equals(MsgCode.MSG_SUCCESS.getCode())) {
                    //保存图片
                    String sb = properties.getUpload_file_location() +
                            File.separator +
                            filename;
                    OutputStream localFile = new FileOutputStream(sb);
                    localFile.write(b);
                    localFile.flush();
                    localFile.close();
                }
                FileDto outFileDto = new FileDto();
                outFileDto.setFileName(filename);
                outList.add(outFileDto);
            }
            out.setData(outList);
            return out;
        } catch (IOException e) {
            throw new IllegalArgumentException("文件保存失败");
        }
    }

    @Override
    public Resp<FileDto> saveFormDataImage(MultipartFile in) {
        System.out.println(in.getOriginalFilename());
        Resp<FileDto> out = new Resp<>();

        try{
            String[] fileType = in.getOriginalFilename().split("\\.");

            // 生成保存路径
            FileDto fileIn = new FileDto();
            fileIn.setFileType(fileType[fileType.length-1]);
            Resp<String> resp = checkCachedFile(fileIn, in.getBytes());
            String filename = resp.getData();
            // 当code为success时为新文件，保存
            if (resp.getCode().equals(MsgCode.MSG_SUCCESS.getCode())){
                //保存图片
                String sb = properties.getUpload_file_location() +
                        File.separator +
                        filename;
                OutputStream localFile = new FileOutputStream(sb);
                localFile.write(in.getBytes());
                localFile.flush();
                localFile.close();
            }
            FileDto outFileDto = new FileDto();
            outFileDto.setFileName(filename);
            out.setData(outFileDto);

            return out;
        }catch (IOException | NullPointerException e){
            throw new IllegalArgumentException("文件保存失败");
        }
    }

    /**
     * 检查上传的文件是否存在，如果存在返回文件名，不存在就存入文件缓存
     * @param in,data
     * @return Resp 如果文件已存在，返回error的code，不存在则为success的code
     */
    private Resp<String> checkCachedFile(FileDto in,byte[] data){
        if (StringUtils.isBlank(in.getFileType())){
            throw new IllegalArgumentException("文件类型不能为空");
        }
        // 计算md5
        String md5 = DigestUtils.md5DigestAsHex(data);
        FileDto check = new FileDto();
        check.setFileMd5(md5);
        int count = fileDao.listFilesCount(BeanConvertUtil.beanCovertMap(check));

        // 文件存在
        if (count == 1){
            List<Map> list = fileDao.listFiles(BeanConvertUtil.beanCovertMap(check));
            List<FileDto> fileDtos = BeanConvertUtil.covertBeanList(list, FileDto.class);
            FileDto fileDto = fileDtos.get(0);
            Resp<String> resp = new Resp<>();
            resp.setCode(MsgCode.MSG_ERROR.getCode());
            resp.setData(fileDto.getFileName()+"."+fileDto.getFileType());

            logger.info("已存在的文件: {}",resp.getData());
            return resp;
        }

        String filename = Base64Util.newUUID().substring(0,25);
        check.setFileName(filename);
        check.setFileType(in.getFileType());
        fileDao.addFile(BeanConvertUtil.beanCovertMap(check));

        Resp<String> resp = new Resp<>();
        resp.setData(filename+"."+in.getFileType());

        logger.info("新存入的文件: {}",resp.getData());
        return resp;
    }
}
